#include <stdlib.h>
#include <stdio.h>
#include <video-graphics.h>
#include "window.h"
#include "level.h"
#include "input.h"
#include "physics.h"
#include "global.h"
#include "xpm.h"
#include "anim.h"
#include "game.h"

#include <kbc.h>

/** Duração de cada quadro da animação em milisegundos */
#define ALEX_ANIM_MSEC 125

/** Janela com o alex kidd */
static Window alex_win;

/** Animações do Alex */
static Animation alex_anim;

/** Física do Alex Kidd */
static Physics alex_phys;

/** Coordenadas originais */
static int orig_x, orig_y;

/** Estrutura usada para dizer quais teclas foram premidas */
static struct AlexKeys {
	Bool upEnabled;
	Bool up;
	Bool down;
	Bool left;
	Bool right;
} keys;

/** Lê dados do teclado */
static Bool alex_keyboard_cb (unsigned char scan_code, void *data)
{
	Bool arrow_sc = true;
	
	// Obtém o estado das teclas
	if (scan_code == SC_UP) keys.up = true;
	else if(scan_code == SC_DOWN) keys.down = true;
	else if(scan_code == SC_LEFT) keys.left = true;
	else if(scan_code == SC_RIGHT) keys.right = true;
	else if(scan_code == release(SC_UP)) keys.up = false;
	else if(scan_code == release(SC_DOWN)) keys.down = false;
	else if(scan_code == release(SC_LEFT)) keys.left = false;
	else if(scan_code == release(SC_RIGHT)) keys.right = false;
	else arrow_sc = false; // Não é um dos scan codes reconhecidos
		

	return arrow_sc;
}

/** Move o ecrã */
static void move_screen (Window alex_win)
{
	// Obtém as coordenadas da janela do Alex Kidd
	int sx, sy, sw, sh;
	window_get_rect (alex_win, &sx, &sy, &sw, &sh);
	
	int ex = sx - HRES/2 + sw/2;
	int ey = sy - VRES/2 + sh/2;

	int mw, mh; // tamanho do mapa
	level_get (NULL, &mw, &mh);

	if (ex < 0) ex = 0;
	else if (ex >= mw * xpm_level_cell_width - HRES) ex = mw * xpm_level_cell_width - HRES;
	if (ey < 0) ey = 0;
	else if (ey >= mh * xpm_level_cell_height - VRES) ey = mh * xpm_level_cell_height - VRES;
	
	winsys_set_coord (ex, ey);

}


static void alex_update_cb (Window win, void *data)

{
	// Desloca usando a física
	if(keys.up) {
		if (keys.upEnabled) {
			/*if(alex_phys.mode !=PHYS_HELI) {
				if(alex_phys.vy==0)
					alex_phys.vy += alex_phys.vy_inc;
			} else if (alex_phys.vy >= 0) {
				//if(vy<=0 || (scan_code == release(SC_UP)))
				alex_phys.vy += alex_phys.vy_inc;
			}*/
			
			alex_phys.vy += alex_phys.vy_inc;
			alex_phys.y_stop = false;
			if (alex_phys.vy >= alex_phys.vy_max)
				keys.upEnabled = false;

		} else if (alex_phys.vy == 0) {
			keys.upEnabled = true;
		}
	} else {
		keys.upEnabled = (alex_phys.vy == 0);

		if (alex_phys.vy > 0)
			alex_phys.y_stop = true;
	}

	if(keys.down) {
		alex_phys.vy += alex_phys.vy_dec;
		alex_phys.y_stop = false;
	}
	
	if(keys.left) {
		alex_phys.vx += alex_phys.vx_dec;
		alex_phys.x_stop = false;
	}
	
	if(keys.right) {
		alex_phys.vx += alex_phys.vx_inc;
		alex_phys.x_stop = false;
	} else if (alex_phys.mode == PHYS_BYKE) {
		if (alex_phys.vx<alex_phys.vx_min) {
			alex_phys.vx = alex_phys.vx_inc;
			alex_phys.x_stop = false;
		}
	}

	int sx, sy;
	physics_alex (&alex_phys, &sx, &sy);

	window_move (alex_win, sx, sy);
	// Move o ecrã
	move_screen (alex_win);
}

static void alex_show_cb (Window win, int x, int y, int w, int h, void *data)
{
	enum AnimID id;

	if (alex_phys.mode == PHYS_NORMAL) {
		// Obtém a animação

	// Se o Alex está no ar
	if (alex_phys.vy != 0) {
		if (alex_phys.vx > 0) { // Se o alex indo para a direita
			id = ANIM_ALEX_JR;
		} else if (alex_phys.vx < 0) { // Se o alex está andando para a esquerda
			id = ANIM_ALEX_JL;
		// Se o alex está virado para a esquerda
		} else if (alex_anim.id == ANIM_ALEX_L || alex_anim.id == ANIM_ALEX_JL) {
			id = ANIM_ALEX_JL;
		} else {
			id = ANIM_ALEX_JR;
		}

	} else if (alex_phys.vx > 0) { // Se o alex está andando para a direita
		id = ANIM_ALEX_WR;

	} else if (alex_phys.vx < 0) { // Se o alex está andando para a esquerda
		id = ANIM_ALEX_WL;
	// Se o alex está virado para a esquerda
	} else if (alex_anim.id == ANIM_ALEX_L
			|| alex_anim.id == ANIM_ALEX_JL
			|| alex_anim.id == ANIM_ALEX_WL) {
		id = ANIM_ALEX_L;
	} else {
		id = ANIM_ALEX_R;
	}

	// Se a animação não mudou, a continuamos 
	if (id == alex_anim.id) {
		xpm_draw (win, anim_continue(&alex_anim), 0, 0);
	} else { // Senão a trocamos
		anim_init (&alex_anim, id, ALEX_ANIM_MSEC);
		xpm_draw (win, anim_play (&alex_anim), 0, 0);
	}
	/*window_draw_int (win, alex_phys.x_stop, 0, 0, 72);
	window_draw_int (win, alex_phys.y_stop, 0, 20, 72);*/


	} else /*	if (alex_phys.mode == PHYS_HELI) */{
		if (alex_phys.vx > 0) { // Se o alex indo para a direita
			id = ANIM_HELI_R;
		} else if (alex_phys.vx < 0) { // Se o alex está andando para a esquerda
			id = ANIM_HELI_L;
		// Se o alex está virado para a esquerda
		} else {
			id = alex_anim.id;
		}
		if (id == alex_anim.id) {
			xpm_draw (win, anim_continue(&alex_anim), 0, 0);
		} else { // Senão a trocamos
			anim_init (&alex_anim, id, ALEX_ANIM_MSEC);
			xpm_draw (win, anim_play (&alex_anim), 0, 0);
		}
	}
}

extern Bool game_quit;

/** Callback chamada quando o sprite é morto */
static void alex_killed_cb (Window win, void *data)
{
	game_life_lose ();
	// Move a janela
	window_move (win, orig_x, orig_y);
	// Obtém coordenadas da janela
	int x, y, w, h;
	window_get_rect (win, &x, &y, &w, &h);

	// Inicializa a física
	physics_init (&alex_phys, PHYS_NORMAL, x, y - 1, w, h);
//	game_quit = true;
}

/* Inicializa o personagem Alex Kidd */		
void alex_sprite_init (int x, int y, LevelSprite sprite)
{
	int phys;

	// Inicializa a física
	switch (game_level_num ()) {
		case 1:
		case 3:
		case 4:
			phys = PHYS_NORMAL;
			anim_init (&alex_anim, ANIM_ALEX_R, ALEX_ANIM_MSEC);
			break;
		case 2:
		case 6:
		case 8:
			anim_init (&alex_anim, ANIM_HELI_R, ALEX_ANIM_MSEC);
			phys = PHYS_BYKE;
			break;
		default:
			anim_init (&alex_anim, ANIM_HELI_R, ALEX_ANIM_MSEC);
			phys = PHYS_HELI;
			break;

	}
	// Inicializa a animação
	//anim_init (&alex_anim, ANIM_ALEX_R, ALEX_ANIM_MSEC);
	XPM alexsprite = anim_play (&alex_anim);

	// Usamos um XPM do alex para obter os tamanhos
	int wx, wy;

	wx = (x+1) * xpm_level_cell_width - alexsprite->width;
	wy = (y+1) * xpm_level_cell_height - alexsprite->height;
	
	physics_init (&alex_phys,
			phys,
			wx,
			wy,
			alexsprite->width,
			alexsprite->height);

	//physics_init (&alex_phys, PHYS_NORMAL, wx, wy-1, alexsprite->width, alexsprite->height);

	orig_x = wx;
	orig_y = wy;

	// Constroi a janela
	alex_win = window_new ( wx, wy, alexsprite->width, alexsprite->height, NULL);
	window_set_plane (alex_win, PLANE_PLAYER);
	window_update (alex_win, alex_update_cb);
	window_show (alex_win, alex_show_cb);
	move_screen (alex_win);

	// Passa ao mapa os dados do sprite
	level_sprite_init (sprite,
			   alex_win,
			   alex_killed_cb,
			   level_callback_delwin,
			   xpm_level_cell_width,
			   xpm_level_cell_height,
			   NULL);

	// Usa o teclado
	input_keyboard_register (alex_keyboard_cb, NULL, false);
	keys.upEnabled = true;
}


/** Callback chamada quando o bolo é comido */
static void cake_killed_cb (Window win, void *data)
{
	// Avança o jogo
	window_delete (win);
	game_next ();
}

static void cake_show_cb (Window win, int x, int y, int w, int h, void *data)
{
	XPM xpm = xpm_get (XPM_CAKE);
	xpm_draw (win, xpm, 0, 0);
}

/** Bolo */
void cake_sprite_init (int x, int y, LevelSprite sprite)
{
	// Imagem do bolo
	XPM xpm = xpm_get (XPM_CAKE);
	
	// Obtém a posição da janela
	int wx = (x+1) * xpm_level_cell_width - xpm->width;
	int wy = (y+1) * xpm_level_cell_height - xpm->height;

	// Criamos a janela
	Window win = window_new (wx, wy, xpm->width, xpm->height, NULL);
	// Pomos a janela no plano dos inimigos
	window_set_plane (win, PLANE_ENEMY);
	// Mostramos a janela
	window_show (win, cake_show_cb);

	// Passamos ao nível os dados sobre este sprite
	level_sprite_init (sprite,
			   win,
			   cake_killed_cb,
			   level_callback_delwin,
			   xpm_level_cell_width,
			   xpm_level_cell_height,
			   NULL);
}

